#include<iostream>
#include<thread>
#include<future>
#include<chrono>
#include<memory>

//future 是c++11当中的模版类，表示一个异步操作的结果，当我们在多线程编程中使用一步任务的时候，std::future 可以帮助我们在需要的时候获取任务的执行结果
//其中的重要特性就是能够阻塞当前线程，直到异步操作完成，从而确保在获取结果的时候不会遇见未完成的操作
//有三种：std::async.创建并运行一个异步任务，返回一个与该任务相关的future 对象
//std::package_task 与 std::future 绑定在一起的模版，是一种对任务的封装。我们可以通过std::package_task 对象获取任务的相关关联的 std::future 对象，通过调用get_future
//方法获取；
//std::promise 和std::future 配合，在函数内部向primose 对象中设置数据就可以拿到这个函数的返回值信息 --> 手动让std::future 就绪
// int Add(int num1 , int num2)
// {
//     std::cout << "加法!" << std::endl;
//     return num1+num2;
// }

//1\、async + future 
// int main()
// {
//     //async 有两个版本，其中哦一个需要填写策略， std::launch::async 表示内部执行的时候内部会创建一个线程执行该任务
//     //异步执行；std::launch::deferred 表示阻塞等待异步任务的执行
//     //deferr : 推迟  async : 异步
//     std::cout << "------------------1-------------" << std::endl;
//     //std::launch::deferred 在get 获取异步结果的时候才会去执行和这个异步任务，有点“懒汉”的味道
//     // std::future<int> result = async(std::launch::deferred , Add , 10 ,20);
//     //std::launch::async 遇见了这个任务就会自己开辟线程去直接异步执行这个任务，有点“饿汉”的味道
//     std::future<int> result = async(std::launch::async , Add , 10 ,20);
//     std::this_thread::sleep_for(std::chrono::seconds(1));//让异步操作完全执行完
//     std::cout << "------------------2-------------" << std::endl;

//     //通过get 函数获取future 对象中保存的值
//     int sum = result.get();
//     std::cout << "------------------3-------------" << std::endl;

//     std::cout << "sum: " << sum << std::endl; 
//     return 0;
// }

//通过传址传参的方式获取数据同时保证了获取数据的时候一定是设置了
// void Add(int num1 , int num2 , std::promise<int> & prom)
// {
//     std::cout << "加法!" << std::endl;
//     // return num1+num2;
//     prom.set_value(num1+num2);
// }

// //2、promise + future
// int main()
// {
//     //创建promise 对象
//     std::promise<int> prom;
//     //获取future对象
//     std::future<int> fu = prom.get_future();//通过promise 中的get_future 函数获取future
//     //异步执行
//     std::thread thr(Add , 10,20,std::ref(prom));//去调用这个函数
//     //获取future 中的数据
//     int ret =  fu.get();
//     std::cout << "sum : " << ret <<std::endl;
//     //等待线程退出
//     thr.join();
//     return 0;
// }

//3、package_task 
//package_task 是一个模版类，实例化的对象可以对一个函数进行进一步的封装，并且可以通过 get_future 获得一个future 对象，来获取封装的这个函数的异步执行结果
int Add(int num1 , int num2)
{
    std::cout << "加法!" << std::endl;
    return num1+num2;
}

int main()
{
    std::packaged_task<int(int,int)> task(Add);//对函数的封装，类模版类型为函数类型


    //package_task 对象可以向函数那样使用，但是不能像函数那样传递，只能通过指针
    //创建一个线程执行Add函数，实现异步执行
    auto ptask = std::make_shared<std::packaged_task<int(int,int)>>(Add);
        //通过get_future 来获取这个函数异步执行的结果
    std::future<int> fu = ptask->get_future();
    std::thread thr([ptask](){
        (*ptask)(10,20);
    });

    int sum = fu.get();
    std::cout << "sum: " << sum << std::endl;
    //最后记得当代==等待线程退出
    thr.join();
    return 0;
}